package com.example.framework.security.core.handler;

import cn.hutool.core.util.ObjectUtil;
import com.example.framework.common.exception.ServiceException;
import com.example.framework.common.pojo.R;
import com.example.framework.common.util.servlet.ServletUtils;
import com.example.framework.security.config.SecurityProperties;
import com.example.framework.security.core.util.JwtTokenUtils;
import com.example.framework.security.core.util.SecurityFrameworkUtils;
import com.example.framework.web.core.handler.GlobalExceptionHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;

@Slf4j
@RequiredArgsConstructor
public class LogoutHandlerImpl implements LogoutHandler {

    private final SecurityProperties securityProperties;

    private final JwtTokenUtils jwtTokenUtils;

    private final GlobalExceptionHandler globalExceptionHandler;

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        // Spring Security 对"/logout"没有 token 校验，只要是"/logout"都会进入此方法
        // 只有登录接口已经登录后有 token 的情况下才会设置 authentication，这里没有执行 TokenAuthenticationFilter，因此 authentication 为 null，所以只能通过 token 判断是否登录了
        try {
            String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getHeaderName());
            if (ObjectUtil.isNotEmpty(token)) {
                jwtTokenUtils.checkAccessToken(token);
                String userId = jwtTokenUtils.getUserIdFromToken(token);
                String deviceId = jwtTokenUtils.getDeviceIdFromToken(token);
                jwtTokenUtils.removeToken(userId, deviceId);
            }
        } catch (ServiceException ignored) {
            // 这里不抛业务异常了，无效token就不处理
        } catch (Throwable ex) {
            log.error("处理退出登录异常：", ex);
            R<?> result = globalExceptionHandler.allExceptionHandler(ex);
            ServletUtils.writeJSON(response, result);
        }
    }
}
